package yx1;

import java.io.*;

/**
 * 工具类：使用序列化和反序列化实现对象的克隆
 *
 * @author oy
 * @version 1.0
 * @date 2018年8月9日
 * @time 下午8:59:23
 */
public class cloneUtil {
    private cloneUtil() {
    }

    //@SuppressWarnings。该批注的作用是给编译器一条指令，告诉它对被批注的代码元素内部的某些警告保持静默。
    @SuppressWarnings("unchecked")
     /*
    序列化 - Serializable
    定义：将实现了Serializable接口（标记型接口）的对象转换成一个字节数组，并可以将该字节数组转为原来的对象。
     */
    public static <T extends Serializable> T cloneObject(T obj) {
        T cloneObj = null;

        // 序列化
        //字节数组输出流在内存中创建一个字节数组缓冲区，所有发送到输出流的数据保存在该字节数组缓冲区中
        ByteArrayOutputStream bout = null;
        //ObjectOutputStream 是专门用来输出对象的输出流；
        ObjectOutputStream oos = null;
        try {
            bout = new ByteArrayOutputStream();//创建一个用来存放输出流的空间
            oos = new ObjectOutputStream(bout);//关联缓冲区空间
            //简单说就是把传入类的属性信息依次写入刚才创建的空间
            oos.writeObject(obj);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            close(oos);
            close(bout);
        }

        // 反序列化
        ByteArrayInputStream bin = null;
        ObjectInputStream ois = null;
        try {
            bin = new ByteArrayInputStream(bout.toByteArray());//toByteArray()方法创建一个大小与此输出流的当前大小的一个新分配缓冲区。
            ois = new ObjectInputStream(bin);
            //readObject方法读取正常应该被序列化的字段信息后，再构造出一个map，再通过对象流，将原有通过对象流写进文件里面的map信息（容量，每个item信息等）全部读取出来，然后重新构造一个map，这样就使得我们保存在set里面的信息，在经历过对象流的序列化和反序列化后，都没有丢失。
            //读取写入的流在创建一个新的对象
            cloneObj = (T) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            close(ois);
            close(bin);
        }

        return cloneObj;
    }

    private static void close(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
